package com.cuanbo.dualscreenteachzhu.utils;

import android.content.Context;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import com.cuanbo.dualscreenteachzhu.base.App;
import com.cuanbo.dualscreenteachzhu.bean.TagBean;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 日志工具类
 */
public class LogUtil {
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
    private static SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMdd");
    //允许最大的文件大小，单位M
    private static int allowMaxFileSize = 1024;
    //当不指定文件名时，默认写入日志到该文件下
    private static String defaultLogFilename = "log";
    //日志默认的输出标记
    private static String defaultTag = "LogUtil";
    private static String defaultErrorLogFilename = "错误";
    private static String defaultErrorTag = "ErrorLog";
    //当上一次打印的内容与下一次打印的内容一模一样时过滤掉
    private static boolean repeatContentFilter = false;
    //是否保存日志到文件中
    private static boolean saveLogToFile = true;
    private TagBean oldTagBean = new TagBean("", "", "");
    private static List<TagBean> tagList = new ArrayList<>();
    private static LogUtil instance;
    private static boolean loop;
    private static String dir;
    public static Object lock = new Object();

    private LogUtil() {
        loop = true;
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (loop) {
                    try{
                        writeLogToFile(getData());
                    }catch (Exception e){
                        LogUtil.addError(e);
                    }
                }
            }
        }).start();
    }

    public static void init(Context context) {
        if (instance == null) {
            dir = context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath() + "/log";
            instance = new LogUtil();
        }
    }

    public static LogUtil getInstance() {
        return instance;
    }

    /**
     * 允许文件的最大大小，当超过该大小时，将会清空文件内容，单位M
     */
    public static void setAllowMaxFileSize(int allowMaxFileSize) {
        LogUtil.allowMaxFileSize = allowMaxFileSize;
    }

    /**
     * 是否过滤重复内容
     */
    public static void setRepeatContentFilter(boolean repeatContentFilter) {
        LogUtil.repeatContentFilter = repeatContentFilter;
    }

    /**
     * 是否保存日志到文件
     */
    public static void setSaveLogToFile(boolean saveLogToFile) {
        LogUtil.saveLogToFile = saveLogToFile;
    }

    /**
     * 设置默认日志的文件名
     */
    public static void setDefaultLogFilename(String defaultLogFilename) {
        LogUtil.defaultLogFilename = defaultLogFilename;
    }

    /**
     * 设置默认日志标记
     */
    public static void setDefaultTag(String defaultTag) {
        LogUtil.defaultTag = defaultTag;
    }

    /**
     * 设置默认错误日志文件名
     */
    public static void setDefaultErrorLogFilename(String defaultErrorLogFilename) {
        LogUtil.defaultErrorLogFilename = defaultErrorLogFilename;
    }

    /**
     * 设置默认错误标记
     */
    public static void setDefaultErrorTag(String defaultErrorTag) {
        LogUtil.defaultErrorTag = defaultErrorTag;
    }

    //写日志到文件中并打印到控制台
    private void writeLogToFile(TagBean bean) {
        if (bean == null) {
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return;
        }
        //启用过滤时，当上一次打印与下一次打印一模一样时将会过滤掉
        if (repeatContentFilter) {
            if (bean.getTag().equals(oldTagBean.getTag()) && bean.getContent().equals(oldTagBean.getContent()) && bean.getFileName().equals(oldTagBean.getFileName()))
                return;
        }
        oldTagBean = bean;
        Log.i(bean.getFileName() + " " + bean.getTag(), bean.getContent());
        //在调试模式下所有日志会强制写入到文件中
        if (!saveLogToFile || TextUtils.isEmpty(bean.getFileName()) || !bean.isWriteToFile())
            return;
        //String nowDate = sdf.format(new Date());
        String nowYYMMDD = sdf2.format(new Date());
        String path = dir + "/" + nowYYMMDD + "/" + App.configInfo.getClassName() + "_" + nowYYMMDD + "_" + bean.getFileName() + ".txt";
        File fDir = new File(dir);
        File fDirYMD = new File(dir + "/" + nowYYMMDD);
        //创建文件夹
        fDir.mkdirs();
        fDirYMD.mkdirs();
        File f = new File(path);
/*        boolean append = true;
        if (f.exists() && f.isFile()) {
            if (f.length() > allowMaxFileSize * 1024 * 1024) {//当数据超过上限时,清空日志文件重新写入数据
                append = false;
            }
        }*/
        try {
            BufferedWriter writer = new BufferedWriter(
                    new OutputStreamWriter(
                            new FileOutputStream(f, true), "GBK"));
            String content = bean.getNowDate() + " " + bean.getTag() + " : " + bean.getContent();
            writer.write(content);
            //writer.write(System.getProperty("line.separator"));
            writer.write("\r\n");
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (FileUtil.getFileSize(fDir) > allowMaxFileSize * 1024 * 1024l) {//当数据超过上限时,清空日志文件夹重新写入数据
            FileUtil.deleteAllFile(fDir);
        }
    }

    //获取日志的使用率
    public static int getUseRate() {
        try {
            return (int) Math.ceil(FileUtil.getFileSize(new File(dir)) * 1d / (allowMaxFileSize * 1024 * 1024d) * 100);
        } catch (Exception e) {}
        return -1;
    }

    //从队列中拉取数据
    private TagBean getData() {
        TagBean bean = null;
        synchronized (lock) {
            if (tagList.size() > 0) {
                bean = tagList.get(0);
                tagList.remove(0);
            }
        }
        return bean;
    }

    /**
     * 清空所有日志
     */
    public static void clearAllLog() {
        FileUtil.deleteAllFile(new File(dir));
        LogUtil.add("LogUtil", "清空所有日志", "日志操作");
    }

    /**
     * 往队列中添加日志数据
     *
     * @param bean 日志数据
     */
    private static void add(TagBean bean) {
        /*if (App.showLogcat) {
            //将日志信息以广播的形式发送出去
            BroadcastUtil.sendLogBroadcast(bean);
        }*/
        synchronized (lock) {
            tagList.add(bean);
            //通知日志写入线程工作
            lock.notifyAll();
        }
    }

    /**
     * 往队列中添加日志数据
     *
     * @param tag         标记
     * @param content     内容
     * @param fileName    要写入到哪个文件中,当为null时不写入到文件
     * @param writeToFile 是否写入到文件中
     */
    public static void add(String tag, String content, String fileName, boolean writeToFile) {
        if (content == null) return;
        if (tag == null) {
            tag = defaultTag;
        }
        if (fileName == null) {
            fileName = defaultLogFilename;
        }
        add(new TagBean(tag, content, fileName, writeToFile));
    }

    /**
     * 往队列中添加日志数据
     *
     * @param tag      标记
     * @param content  内容
     * @param fileName 要写入到哪个文件中
     */
    public static void add(String tag, String content, String fileName) {
        if (content == null) return;
        if (tag == null) {
            tag = defaultTag;
        }
        if (fileName == null) {
            fileName = defaultLogFilename;
        }
        add(new TagBean(tag, content, fileName));
    }

    /**
     * 往队列中添加日志数据,未指定文件名将写入到默认文件中
     *
     * @param tag     标记
     * @param content 内容
     */
    public static void add(String tag, String content) {
        add(new TagBean(tag, content, defaultLogFilename));
    }

    /**
     * 往队列中添加日志数据,未指定文件名和标记，将使用默认文件和标记
     *
     * @param content 内容
     */
    public static void add(String content) {
        add(new TagBean(defaultTag, content, defaultLogFilename));
    }

    /**
     * 关闭日志
     */
    public static void close() {
        synchronized (lock) {
            loop = false;
            lock.notifyAll();
            instance = null;
        }
        Log.i("LogUtil_", "日志线程已结束");
    }

    /**
     * 当上一次打印的日志与当前打印的日志，标记丶内容丶输入文件一模一样时过滤
     *
     * @param repeatContentFilter true:过滤 false:不过滤
     */
    public static void repeatContentFilter(boolean repeatContentFilter) {
        LogUtil.repeatContentFilter = repeatContentFilter;
    }

    private static Throwable getLastCause(Throwable e) {
        if (e != null && e.getCause() != null) {
            return getLastCause(e.getCause());
        }
        return e;
    }

    /**
     * 记录一条错误日志
     *
     * @param t 线程对象
     * @param e 错误对象
     */
    public static void addError(Thread t, Throwable e) {
        Throwable cause = getLastCause(e);
        add(defaultErrorTag, "ThreadName:" + t.getName(), defaultErrorLogFilename);
        add(defaultErrorTag, cause.toString(), defaultErrorLogFilename);
        StackTraceElement[] seCause = cause.getStackTrace();
        for (int i = 0; i < seCause.length; i++) {
            add(defaultErrorTag, "    at " + seCause[i].getClassName() + "." + seCause[i].getMethodName() + "(" + seCause[i].getFileName() + ":" + seCause[i].getLineNumber() + ")", defaultErrorLogFilename);
        }
        add(defaultErrorTag, "-------------------------------------------------------------", defaultErrorLogFilename);
    }

    /**
     * 记录一条错误日志
     *
     * @param e 错误对象
     */
    public static void addError(Throwable e) {
        addError(Thread.currentThread(), e);
    }

    /**
     * 记录一条错误日志
     *
     * @param text 要记录的文本内容
     */
    public static void addError(String text) {
        add(defaultErrorTag, text, defaultErrorLogFilename);
    }
}
